#include <pthread.h>
#include <iostream>
using namespace std;
#include "sys/thread.h"
using namespace tdl;

int gi = 0;
rw_lock rwl;
mutex_lock mtx;
spin_lock spin;
empty_lock empty;

template <typename Tlock>
void inc_main(Tlock* plk)
{
	locker<Tlock> l(*plk);
	for(int i = 0; i < 1000000; ++i)
	{
		l.lock(true);		// as writer
		gi++;
		l.unlock();
	}
}

template <typename Tlock>
void dec_main(Tlock* plk)
{
	for(int i = 0; i < 1000000; ++i)
	{
		auto_locker<Tlock> al(*plk, true);	// as writer
		gi--;
	}
}

template <typename Tlock>
void watch_main(Tlock* plk)
{
	locker<Tlock> l(*plk);
	for(int i = 0; i < 10; ++i)
	{
		if(! l.trylock(false))		// as reader
			cout << "trylock failed" << endl;
		else
		{
			cout << "watch: " << gi << endl;
			l.unlock();
		}
		usleep(10);
	}
}

void foo(int x)
{
	cout << "foo(int): " << x << endl;
}

//////////////////
int main(int argc, char* argv[])
{

	// test for mutex
	gi = 0;
	cout << "----- test for empty_lock -----" << endl;
	thread th_inc(make_fun_exec(&inc_main<empty_lock>, &empty), false);
	thread th_dec(make_fun_exec(&dec_main<empty_lock>, &empty), false);
	thread th_watch(make_fun_exec(&watch_main<empty_lock>, &empty), false);
	th_inc.run();
	th_dec.run();
	th_watch.run();
	th_inc.wait();
	th_dec.wait();
	th_watch.wait();
	cout << "finally gi=" << gi << endl << endl;

	gi = 0;
	// test for mutex
	cout << "----- test for mutex -----" << endl;
	executor* e1 = make_fun_exec(&inc_main<mutex_lock>, &mtx);
	th_inc.run(e1, false, false);
	executor* e2 = make_fun_exec(&dec_main<mutex_lock>, &mtx);
	th_dec.run(e2, false, false);
	executor* e3 = make_fun_exec(&watch_main<mutex_lock>, &mtx);
	th_watch.run(e3, false, false);
	th_inc.wait();	delete e1;
	th_dec.wait();	delete e2;
	th_watch.wait();	delete e3;
	cout << "finally gi=" << gi << endl << endl;

	// test for rwlock
	gi = 0;
	cout << "----- test for rwlock -----" << endl;
	th_inc.run(make_fun_exec(&inc_main<rw_lock>, &rwl), false);
	th_dec.run(make_fun_exec(&dec_main<rw_lock>, &rwl), false);
	th_watch.run(make_fun_exec(&watch_main<rw_lock>, &rwl), false);
	th_inc.wait();
	th_dec.wait();
	th_watch.wait();
	cout << "finally gi=" << gi << endl << endl;

	// test for spinlock	
	gi = 0;
	cout << "----- test for spinlock -----" << endl;
	th_inc.run(make_fun_exec(&inc_main<spin_lock>, &spin), false);
	th_dec.run(make_fun_exec(&dec_main<spin_lock>, &spin), false);
	th_watch.run(make_fun_exec(&watch_main<spin_lock>, &spin), false);
	th_inc.wait(); th_dec.wait(); th_watch.wait();
	cout << "finally gi=" << gi << endl << endl;

	// test for thread
	cout << "----- test for thread -----" << endl;
	e1 = make_fun_exec(&foo, 3);
	thread th_foo(e1, false, false);
	th_foo.run();	th_foo.wait();	
	th_foo.run();	th_foo.wait();

	// test for thread_pool
	cout << "----- test for thread_pool -----" << endl;
	thread_pool tp(5, e1);
	tp.run();
	usleep(1000);

	// test for timer
	cout << "----- test for timer -----" << endl;
	timer tth;
	tth.initialize(1000000, 3);
	tth.run(make_fun_exec(&foo, 8), false);
	tth.wait();

	return 0;
}

